microCMSとNext.jsを組み合わせて、Jamstackなブログを作成することができるチュートリアルです。
前提
利用サービス
本記事では以下の2つのウェブサービスを利用します。どちらのサービスも個人開発においては無料の範囲で十分な機能を備えており、実績豊富なサービスです。最初にそれぞれのサイトトップより登録を済ませておきましょう。
- microCMS:特に日本市場において広く利用されているヘッドレスCMSです。ブログのコンテンツ管理を担います。
- Vercel:フロントエンド開発向けのプラットフォームです。サイト公開におけるインフラやCI/CDを担います。
ソフトウェアバージョン
下記のバージョンで開発を行なっています。バージョンの差異によって若干機能が異なる可能性があります。
- Next 13.1.1
- react 18.2.0
- react-dom 18.2.0
- microcms-js-sdk 2.3.2
1. Next.jsプロジェクトを用意する
まずは、Next.jsのプロジェクトを作成していきます。プロジェクトの雛形を作成するCLIがあるので、コマンドを入力して作成していきましょう。
$ npx create-next-app microcms-next-jamstack-blog
※ create-next-appでプロジェクトを作成した場合、カナリアリリースのバージョンがインストールされるため、上記バージョンと異なる可能性があります。ご注意ください。
そして、作成したプロジェクトに移動して開発サーバーを立ち上げます。
$ cd microcms-next-jamstack-blog
$ npm run dev
localhost:3000にアクセスすると下記の画像のように、アプリケーションが立ち上がります。
2. microCMSを用意する
次に、microCMSでAPIを作成していきます。登録〜APIの作成に関してご不明点があればmicroCMSのドキュメントを参照してください。
それではブログ用のAPIを作成していきます。API作成画面から自分で決めるをクリックしましょう。API名にブログ、エンドポイントにblogを入力してください。そして、次へをクリックしてください。
そして、リスト形式を選択します。次へをクリックしてください。
タイトルと本文のフィールドを用意します。APIスキーマは以下の通りです。最後に完了をクリックして作成を終えましょう。
コンテンツの作成
適当に内容を入力し、公開します。
コンテンツ一覧画面に戻り、画面右上のAPIプレビューをクリックします。
取得ボタンをクリックし、入力内容がAPI経由で取得できるか確認してください(レスポンスJSONが表示されます)。
3. APIキーをenvファイルで保護
microCMSではリクエストにAPIキーを含める事で特定のデータを取得できます。
このAPIキーは、GitHubのパブリックで公開されてしまうのはセキュリティー面でよくありません。
なので、envファイルなどで保護してあげましょう。
.env.development.localファイルを作成します。.localをつけるとローカル環境で使うことができます。
また、.developmentをつけると開発環境で使えます。
API_KEY=xxxxxxxxxxxx
プロジェクト内でAPIキーを参照することができます。
process.env.API_KEY
Next.jsのenvファイルの取り扱いはドキュメントを参照してください。
https://nextjs.org/docs/basic-features/environment-variables
4.microcms-js-sdkの準備
公式で提供しているmicrocms-js-sdk
をインストールしましょう。microcms-js-sdkはオープンソースで公開されています。
https://github.com/microcmsio/microcms-js-sdk
$ npm install --save microcms-js-sdk
そして、libsフォルダ -> client.js
を作成してSDKの初期化を行います。service-domain
とapi-Key
を設定してください。serviceDomain
はXXXX.microcms.io
の場合、XXXX
の部分になります。apiKey
は環境変数を参照してください。
// libs/client.js
import { createClient } from 'microcms-js-sdk';
export const client = createClient({
serviceDomain: 'service-domain',
apiKey: process.env.API_KEY,
});
5. ブログの一覧を表示する
それでは、実際にmicroCMSのデータを取得したページを作成してみましょう。
Next.jsでは、pages/
以下に作成したファイルに基づいて自動的にルーティングされる仕組みになっています。
pages/index.js
→ 記事一覧pages/about.js
→ Aboutページ
pages/index.js
の内容を変更してみましょう。
// pages/index.js
import Link from "next/link";
import { client } from "../libs/client";
export default function Home({ blog }) {
return (
<div>
<ul>
{blog.map((blog) => (
<li key={blog.id}>
<Link href={`/blog/${blog.id}`}>{blog.title}</Link>
</li>
))}
</ul>
</div>
);
}
// データをテンプレートに受け渡す部分の処理を記述します
export const getStaticProps = async () => {
const data = await client.get({ endpoint: "blog" });
return {
props: {
blog: data.contents,
},
};
};
ここで注目してもらいたいのは、getStaticProps
を使ってmicroCMSのデータを取得しているところです。
これは、ビルド時にサーバー側で呼ばれる関数です。この部分の処理は最終的にバンドルJSに含まれません。
ビルド時にデータを取得し、静的なHTMLを出力するために必要です。
また、デフォルトではstyles/globals.css
にてグローバルCSSに背景グラデーションが効いてしまっているので、該当箇所をコメントアウトしておきましょう。
:root {
--max-width: 1100px;
--border-radius: 12px;
--font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono',
'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;
--foreground-rgb: 0, 0, 0;
/* --background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255; */
/* 以下略 */
それでは、再度アプリケーションを立ち上げてみましょう。microCMSのコンテンツがリスト形式で表示できています。
もしエラーが表示される場合は再度npm run dev
で起動し直してみましょう。
6. ブログの詳細を表示する
次に、ブログ記事の詳細画面を作っていきます。
記事の詳細画面のような動的なページは、ファイル名に[] (ブラケット)をつけます。
pages/blog/[id].js
→ 記事の詳細
それでは、pages/
ディレクトリ内にblog/
ディレクトリを作成して、その中に [id].jsを作成します。
// pages/blog/[id].js
import { client } from "../../libs/client";
export default function BlogId({ blog }) {
return (
<main>
<h1>{blog.title}</h1>
<p>{blog.publishedAt}</p>
<div
dangerouslySetInnerHTML={{
__html: `${blog.body}`,
}}
/>
</main>
);
}
// 静的生成のためのパスを指定します
export const getStaticPaths = async () => {
const data = await client.get({ endpoint: "blog" });
const paths = data.contents.map((content) => `/blog/${content.id}`);
return { paths, fallback: false };
};
// データをテンプレートに受け渡す部分の処理を記述します
export const getStaticProps = async (context) => {
const id = context.params.id;
const data = await client.get({ endpoint: "blog", contentId: id });
return {
props: {
blog: data,
},
};
};
※dangerouslySetInnerHTML
はXSSを引き起こす可能性があるため非推奨とされています。
今回の構成においては、入力はmicroCMSのリッチエディタからのみであり、ユーザーからの自由入力箇所ではないため安全であるとして利用しています。
ここではgetStaticPaths
という関数を確認します。
Next.js側ではブログのidを知り得ないため、事前に生成するべきHTMLのパスが分かりません。
そこでこの関数内でデータを取得し、パスを定義してあげる必要があります。
ここでのパスはmicroCMSのコンテンツIDです。
またfallback
をfalseにしています。これで、getStaticPaths
で返されないパスをすべて404ページで返します。
ブラウザで確認してみましょう。詳細ページを作成することができました。
ついでに404ページも作成してみましょう。pages/以下に404.jsを作成すると、静的な404ページを作成することができます。
pages/404.js
→ 404ページ
export default function Custom404() {
return (
<main className="main">
<p>ページがありません。</p>
</main>
);
}
パスがないURLにアクセスすると、404ページが表示されることが確認できます。
7. CSSで見た目を装飾する
microCMSのリッチエディタで記述した内容はHTML形式で取得することができます。
しかし、HTML内にclassを付与することが現状できないので、本文を囲うdivにclassを付与し、タグ指定でcssを書いていきます。
Scssで記述するために、sassをインストールします。
$ npm install --save sass
ここではグローバルレベルのスタイルと、CSS Moduleを使ったコンポーネントレベルのスタイリングを説明していきます。
グローバルスタイルは_app.jsに読み込みます。今回のプロジェクトではすでにスタイルが読み込まれてることが確認できます。
// pages/_app.js
import '../styles/globals.css'
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
そして、CSS Modulesを使ったコンポーネントのレベルのスタイリングです。
CSS Modulesを使うことによって、ローカルのCSSにスコープを効かせることができます。
ファイル名は[name].module.cssのようにmoduleをつけます。
こちらが簡単なスタイリング例です。
.text {
color: red
}
こちらがスタイルの指定方法です。
<p className={styles.text}>これはテキストです</p>
それではスタイリングしていきましょう。
styles/Home.module.cssのファイル名をHome.module.scssに変更して、Scssに対応します。
そして、下記の内容を入力してください。
.main {
width: 960px;
margin: 0 auto;
}
.title {
margin-bottom: 20px;
}
.publishedAt {
margin-bottom: 40px;
}
.post {
& > h1 {
font-size: 30px;
font-weight: bold;
margin: 40px 0 20px;
background-color: #eee;
padding: 10px 20px;
border-radius: 5px;
}
& > h2 {
font-size: 24px;
font-weight: bold;
margin: 40px 0 16px;
border-bottom: 1px solid #ddd;
}
& > p {
line-height: 1.8;
letter-spacing: 0.2px;
}
& > ol {
list-style-type: decimal;
list-style-position: inside;
}
}
そして記事詳細ページはこのようにスタイルを当てていきます。/pages/blog/[id].jsを編集してください。
import { client } from '../../libs/client';
import styles from '../../styles/Home.module.scss';
export default function BlogId({ blog }) {
return (
<main className={styles.main}>
<h1 className={styles.title}>{blog.title}</h1>
<p className={styles.publishedAt}>{blog.publishedAt}</p>
<div
dangerouslySetInnerHTML={{
__html: `${blog.body}`,
}}
className={styles.post}
/>
</main>
);
}
// more
すると、記事詳細ページを確認するとこのような見た目になっています。
8. ビルドして静的ファイルを生成してみる
試しに一度ローカル環境でビルドしてみましょう。
ビルドするために必要な.env.localファイルを作成します。内容は.env.development.localと同じです。
API_KEY=xxxxxxxxxxxx
そして、ビルドしてみましょう。
$ npm run build
すると、ビルドログを確認することができます。/blog/[id] を確認すると動的なページも出力できていることが確認できます。
9. ファイルをホスティングする
Next.jsの開発元でもあるVercel社が運営しているホスティングサービスを使用します。事前にログインを済ませておいてください。
https://vercel.com
まずは、GitHubリポジトリを作成します。
$ git add .
$ git commit -m 'first commit'
$ git remote add origin your-repository // 自分のリポジトリを入力
$ git push -u origin main
Vercelで先ほど作成したリポジトリと連携をしていきます。
ダッシュボード上のNew Projectをクリックします。そして、今回作成したリポジトリを選択して、Import Git Repositoryのimportをクリックしてください。
GitHubにVercelがインストールされていない場合はインストールする必要があります。
自分のアカウントを選択します。
そして、今回作成したリポジトリを選択します。
インポートしたプロジェクトの情報が表示されます。
Build and Output Settings はそのままでOKです。
Environment VariablesにAPI_KEYを入れてVALUEにはmicroCMSのAPIキーを入れてAddをクリックしてください。そしてDeployをクリックしましょう。
デプロイが成功すると下記の画面に移ります。ホスティングに成功しているか確認してみましょう。
10.microCMSとVercelを連携する
現在の設定では、microCMSで記事を更新しても本番環境WEBサイトには反映されません。
なぜなら、静的なサイトでは再度ビルドを行わないと、実際の環境には反映されないからです。
なのでWebhookを利用して、記事の更新時にビルドを走らせる設定にします。
Vercelのダッシュボードで、先ほどデプロイしたプロジェクトのsettingsからGit > Deploy HooksでWebhookを作成します。Hook NameはmicroCMS(ここはお好きな名前で大丈夫です)、Git Branch Nameにはmain(またはmaster)ブランチを指定しましょう。そして、Create Hookをクリックすると、Web HookのURLが発行されます。
発行されたWebhookをmicroCMSの管理画面で設定します。先ほど作成したブログのAPI設定から、カスタム通知を選択して、WebhookのURLを入力してください。
これで、記事を更新するとVercelのビルド開始されて本番環境に内容が反映されます。
11.カテゴリーを追加する
最後に、既存のブログAPIにカテゴリーを追加してみましょう。API名にカテゴリー、エンドポイントにcategoriesを入力してください。
カテゴリーを紐付けるにはコンテンツ参照機能を用います。
先ほどと同じ、リスト形式を選択します。
カテゴリー名のフィールドを用意します。APIスキーマは以下の通りです。最後に完了をクリックして作成を終えましょう。
試しにいくつかカテゴリーコンテンツを入稿してみましょう。
次に、ブログの API設定 > APIスキーマ に新しくカテゴリーフィールドを追加します。
種類はコンテンツ参照で、カテゴリーAPIを指定します。
カテゴリが追加できたらブログのコンテンツ詳細を開き、追加した「カテゴリー」の項目を編集して公開します。
そして、記事の詳細ページにカテゴリーを追加してみましょう。
// pages/blog/[id].js
export default function BlogId({ blog }) {
return (
<main className={styles.main}>
<h1 className={styles.title}>{blog.title}</h1>
<p className={styles.publishedAt}>{blog.publishedAt}</p>
<p>{blog.category && blog.category.name}</p>
<div
dangerouslySetInnerHTML={{
__html: `${blog.body}`,
}}
className={styles.post}
/>
</main>
);
}
これでカテゴリーとして設定した「JavaScript」が、ページにも反映されました!
おわりに
今回はmicroCMSとNext.jsを組み合わせてJamstackアーキテクチャーを利用したブログを作成しました。
ブログを公開したら #microCMS をつけてぜひツイートで教えてください。運営メンバーが楽しく拝見させてもらいます。
また、ブログに機能を追加するうえで参考になる記事もありますのでよければ読んでみてください。
- Next.jsでカテゴリーページを実装してみよう
- Next.js(SSG)でページネーションを実装してみよう
- Next.jsのPreview Mode+Vercelでプレビュー機能を実現する
- imgixで動的画像・OGPを作成する
-----
microCMSは日々改善を進めています。
ご意見・ご要望は管理画面右下のチャット、公式Twitter、メールからお気軽にご連絡ください!
引き続きmicroCMSをよろしくお願いいたします!